import React, { FC, useCallback, useState } from 'react';
import { Modal, Upload as AntdUpload, Space, Input, Slider, Tooltip, message, Alert } from 'antd';
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';
import classNames from 'classnames';
import _ from 'lodash';
import { RcFile, UploadFile, UploadProps as AntdUploadProps } from 'antd/lib/upload/interface';

import { Content, Header } from '@/components/Page';
import Button from '@/components/Button';
import Icons from '@/components/Icons';

import { bytesToSize, fileToBase64String, getPreviewIconUrl } from '@/utils/util';
import { PictureSuffixList, UploadFileSuffix } from '@/enumTypes/upload';
import { COMMON_IMG_ALT } from '@/utils/config';

import cannotPreview from '@assets/images/files/cannotPreview.svg';
import styles from './index.module.less';
import { fileToBase64FileObj } from './utils';
import UploadItemList from './UploadItemList';
import type { Base64FileObj } from './type';

export type UpLoadProps = AntdUploadProps & {
  /**
   * 是否启用图片裁剪功能
   * @default false
   */
  cropEnabled?: boolean;

  /**
   * 图片裁剪打开弹窗标题
   * @default '图片裁剪'
   */
  cropModalTitle?: React.ReactNode;

  /**
   * 单文件上传限制大小(单位为MB)
   * @default '10MB'
   */
  singleFileMaxSize?: number;

  /** 启用裁剪后上传前操作 */
  beforeUpload?: (fileList: Base64FileObj[]) => void;
};

const UpLoad: FC<UpLoadProps> = ({
  cropEnabled = true,
  cropModalTitle = '图片裁剪',
  singleFileMaxSize = 10,
  beforeUpload,
  multiple = true,
  ...rest
}) => {
  const [cropModalOpen, setCropModalOpen] = useState<boolean>(false);

  const [currentFileUid, setCurrentFileUid] = useState<string>('');
  const [beforeUploadFileList, setBeforeUploadFileList] = useState<Base64FileObj[]>([]);

  const [fileList, setFileList] = useState<UploadFile[]>([]);

  const [cropper, setCropper] = useState<any>();
  const [rotate, setRotate] = useState<number>(0);

  /** 启用裁剪处理 */
  const handleBeforeCrop = useCallback(
    _.debounce((fileList: RcFile[]) => {
      Promise.all(fileList.map(_file => fileToBase64FileObj(_file))).then(base64FileList => {
        setCurrentFileUid(base64FileList[0].uid);
        setBeforeUploadFileList(base64FileList);
        setCropModalOpen(true);
      });
    }),
    []
  );

  /** 文件上传前处理，判断是否需要启用裁剪 */
  const handleBeforeUpload = useCallback(
    (file: RcFile, fileList: RcFile[]) => {
      console.log(file, fileList);

      if (cropEnabled) {
        // 启用裁剪
        return new Promise(() => {
          handleBeforeCrop(fileList);
          return false;
        });
      } else {
        if (beforeUpload) {
          // 不启用裁剪，但传入beforeUpload, 返回beforeUpload执行
          return beforeUpload(file, fileList);
        } else {
          return undefined;
        }
      }
    },
    [cropEnabled, handleBeforeCrop]
  );

  /** 点击切换选择文件 */
  const handleChangeCurrentImg = useCallback((uid: string) => {
    setCurrentFileUid(uid);
  }, []);

  /** 修改文件名级联变更 */
  const handleChangeCurrentFileName = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      // 获取当前选中文件
      const currentFile = beforeUploadFileList.find(file => file.uid === currentFileUid);

      // 获取最新的文件名(不含类型后缀)
      const name = e.target.value;
      // 获取最新的文件名(含类型后缀)
      const fullName = e.target.value + (currentFile?.suffix || '');

      // 更新文件列表数据
      const newBeforeUploadFileList = beforeUploadFileList.map((file: Base64FileObj) => {
        if (file.uid === currentFileUid) {
          // 修改时间
          const lastModifiedDate = new Date();
          const lastModified = lastModifiedDate.valueOf();
          return {
            ...file,
            name,
            fullName,
            lastModifiedDate,
            lastModified
          };
        }

        return { ...file };
      });
      setBeforeUploadFileList(newBeforeUploadFileList);
    },
    [beforeUploadFileList, currentFileUid]
  );

  /** 保存当前裁剪完的图片数据 */
  const handleSaveCurrentCropData = useCallback(async () => {
    if (cropper) {
      await cropper
        .getCroppedCanvas({
          imageSmoothingQuality: 'high' // 设置图像平滑的质量“低”（默认）、“中”或“高”之一
        })
        .toBlob(async (blob: Blob) => {
          // 最新文件大小
          const size = blob.size;
          const fullSize = bytesToSize(blob.size);
          const base64Data = await fileToBase64String(blob);
          // 修改时间
          const lastModifiedDate = new Date();
          const lastModified = lastModifiedDate.valueOf();

          // 更新文件列表数据
          const newBeforeUploadFileList = beforeUploadFileList.map((file: Base64FileObj) => {
            if (file.uid === currentFileUid) {
              const previewIconUrl = getPreviewIconUrl(file.suffix as UploadFileSuffix, base64Data);
              return {
                ...file,
                size,
                fullSize,
                base64Data,
                previewIconUrl,
                lastModifiedDate,
                lastModified
              };
            }

            return { ...file };
          });
          setBeforeUploadFileList(newBeforeUploadFileList);
        });
    }
  }, [cropper, beforeUploadFileList, currentFileUid]);

  /** 图片旋转展示 */
  const handleToRotate = useCallback(
    (type: 'right' | 'slider' | 'left', value?: number) => {
      let _rotate = 0;
      switch (type) {
        case 'right':
          _rotate = rotate + 10 > 180 ? 180 : rotate + 10;
          break;
        case 'slider':
          _rotate = value || 0;
          break;
        case 'left':
          _rotate = rotate - 10 < -180 ? -180 : rotate - 10;
          break;
        default:
          break;
      }

      setRotate(_rotate);
      if (cropper) {
        cropper.rotateTo(_rotate);
      }
    },
    [rotate, cropper]
  );

  /** 执行上传 */
  const handleUpload = useCallback(() => {
    try {
      let stashFileList = [...fileList];
      beforeUploadFileList.forEach((file: Base64FileObj, index: number) => {
        // 文件大小校验
        if (singleFileMaxSize && file.size > singleFileMaxSize * 1024 * 1024) {
          message.error(`第${index + 1}个文件大小超过${singleFileMaxSize}MB!`);
          throw new Error();
        }
        // 执行文件上传前操作
        if (beforeUpload) beforeUpload(beforeUploadFileList);
        // 执行文件上传逻辑(目前为模拟)
        const serverFile: UploadFile = {
          lastModified: file.lastModified,
          lastModifiedDate: file.lastModifiedDate,
          name: file.fullName,
          size: file.size,
          status: 'uploading',
          thumbUrl: file.base64Data,
          uid: file.uid,
          percent: (index + 1) * 20,
          type: file.type
        };
        stashFileList.push(serverFile);
        setFileList(stashFileList);
        // 模拟调用接口
        setTimeout(() => {
          stashFileList = [...stashFileList].map(newFile => {
            if (newFile.uid === file.uid) {
              return {
                ...newFile,
                status: 'done',
                percent: undefined
              } as UploadFile;
            }
            return { ...newFile };
          });
          // 更新文件状态
          setFileList(stashFileList);
        }, 500);
      });

      // 关闭窗口
      setCropModalOpen(false);
    } catch {
      /* empty */
    }
  }, [beforeUploadFileList, singleFileMaxSize, fileList]);

  /** 裁剪弹窗标题 */
  const renderCropModalTitle = useCallback(() => {
    return (
      <div className={styles.rbUploadModalTitleWapper}>
        <div>{cropModalTitle}</div>
        {singleFileMaxSize && (
          <Alert message={`单个文件上传最大限制为${singleFileMaxSize}MB`} type="warning" showIcon />
        )}
      </div>
    );
  }, [cropModalTitle, singleFileMaxSize]);

  /** 裁剪弹窗-文件列表区域 */
  const renderCropModalList = useCallback(() => {
    return beforeUploadFileList.map((file: Base64FileObj, index: number) => {
      return (
        <div
          key={file.uid}
          className={styles.listItemWapper}
          onClick={() => handleChangeCurrentImg(file.uid)}
        >
          <div
            className={
              currentFileUid === file.uid
                ? classNames(styles.listItemIndex, styles.listItemIndexActive)
                : styles.listItemIndex
            }
          >
            {index + 1}
          </div>
          <div
            className={
              currentFileUid === file.uid
                ? classNames(styles.listItemImageWapper, styles.listItemImageWapperActive)
                : styles.listItemImageWapper
            }
          >
            <img className={styles.listItemImage} alt={COMMON_IMG_ALT} src={file.previewIconUrl} />
            <div className={styles.listItemImageName}>
              <Tooltip title={file.fullName}>{file.fullName}</Tooltip>
            </div>
            <div className={styles.listItemImageSize}>
              <Tooltip title={file.fullSize}>{file.fullSize}</Tooltip>
            </div>
          </div>
        </div>
      );
    });
  }, [beforeUploadFileList, currentFileUid, handleChangeCurrentImg]);

  /** 裁剪弹窗-裁剪和预览区域 */
  const renderCropAndPreview = useCallback(() => {
    // 获取当前选中文件
    const currentFile = beforeUploadFileList.find(file => file.uid === currentFileUid);
    // 判断是否图片
    const isPicture = PictureSuffixList.includes(currentFile?.suffix as UploadFileSuffix);
    return isPicture ? (
      <div className={styles.cropTopWapper}>
        <Cropper
          className={styles.cropTopCrop}
          zoomTo={0} // 默认缩放
          initialAspectRatio={1}
          dragMode="move" // 拖拽模式
          minCropBoxHeight={50} // 剪切框最小高度
          minCropBoxWidth={50} // 剪切框最小宽度
          rotatable // 启用旋转
          autoCropArea={1} // 默认裁剪框与画布比例
          checkOrientation={false} // 是否启用检查方向
          src={currentFile?.base64Data}
          preview=".rb-crop-upload-current-img-preview" // 预览区域元素
          // 设置cropper对象
          onInitialized={instance => setCropper(instance)}
        />
        <div className={classNames('rb-crop-upload-current-img-preview', styles.cropTopPreview)} />
      </div>
    ) : (
      <div className={styles.cropTopWapper}>
        <div className={styles.cannotPreviewWapper}>
          <img className={styles.cannotPreview} src={cannotPreview} alt={COMMON_IMG_ALT} />
          <div>该文件类型暂不支持裁剪!</div>
        </div>
      </div>
    );
  }, [beforeUploadFileList, currentFileUid]);

  /** 裁剪弹窗-操作按钮区域 */
  const renderOperationBtn = useCallback(() => {
    // 获取当前选中文件
    const currentFile = beforeUploadFileList.find(file => file.uid === currentFileUid);
    // 判断是否图片
    const isPicture = PictureSuffixList.includes(currentFile?.suffix as UploadFileSuffix);
    return (
      <div className={styles.cropBtnWapper}>
        {isPicture && (
          <div className={styles.cropBtnSliderWapper}>
            <Icons
              className={styles.cropBtnIcons}
              type="RedoOutlined"
              rotate={-90}
              onClick={() => handleToRotate('left')}
            />
            <Slider
              className={styles.cropBtnSlider}
              min={-180}
              max={180}
              value={rotate}
              onChange={value => handleToRotate('slider', value)}
            />
            <Icons
              className={styles.cropBtnIcons}
              type="UndoOutlined"
              rotate={90}
              onClick={() => handleToRotate('right')}
            />
          </div>
        )}
        <div className={styles.cropBtnFileName}>
          <Input
            variant={'borderless'}
            prefix="文件名:"
            suffix={currentFile?.suffix}
            value={currentFile?.name}
            className={styles.cropBtnFileNameInput}
            size="small"
            onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleChangeCurrentFileName(e)}
          />
        </div>
        <div className={styles.cropBtnSaveOrUploadWapper}>
          <Space wrap>
            <Button type="primary" shape="default" onClick={handleSaveCurrentCropData}>
              保存
            </Button>
            <Button type="primary" shape="default" onClick={handleUpload}>
              全部上传
            </Button>
          </Space>
        </div>
      </div>
    );
  }, [
    beforeUploadFileList,
    currentFileUid,
    handleChangeCurrentFileName,
    handleSaveCurrentCropData,
    rotate,
    handleToRotate,
    handleUpload
  ]);

  console.log(beforeUploadFileList, fileList);

  return (
    <>
      <Header title="附件上传" backPath="/test-pages" />
      <Content>
        <div className={styles.rbUploadWapper}>
          {/* {fileList.map(file => (
          <UploadItemList key="1" {...file} />
        ))} */}
          <UploadItemList />
          <AntdUpload
            action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
            listType="picture-card"
            beforeUpload={handleBeforeUpload as any}
            // fileList={fileList}
            multiple={multiple}
            showUploadList={false}
            {...rest}
          >
            图片上传
          </AntdUpload>
        </div>
        <Modal
          width="50vw"
          open={cropModalOpen}
          onCancel={() => setCropModalOpen(false)}
          footer={null}
          maskClosable={false}
          title={renderCropModalTitle()}
        >
          <div className={styles.rbUploadModalWapper}>
            <div className={styles.listWapper}>
              <div className={styles.listContentWapper}>{renderCropModalList()}</div>
            </div>
            <div className={styles.cropWapper}>
              {renderCropAndPreview()}
              {renderOperationBtn()}
            </div>
          </div>
        </Modal>
      </Content>
    </>
  );
};

export default UpLoad;
